package com.zero.guava.samples.FilesDemo;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.*;

import java.io.*;
import java.util.List;
import java.util.regex.Pattern;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;


public class FilesDemo {

    public static void main(String[] args) throws Exception {
        String resourceName = "src\\files\\test01";
        String writeName = "src\\files\\test07";
        //testCopyFile();
        //testMoveFile();
        //eadFileIntoListOfStringsTest();
        //readLinesWithProcessor();
        //testFilesHashing();
        //appendingWritingToFileTest();
        //createByteSourceFromFileTest();
        //testCreateFileByteSink();
        //copyToByteSinkTest();
        //limitByteStreamTest();
        //joinTest();
        //inputStreamSupplierTest();
        //jdkInputStreamTest("src\\files\\test01");
        //readerAndWriterTest(resourceName,writeName);
        //testCloser();
        encodeDecodeTest();
    }

    /**
     * 文件复制
     */
    public static void testCopyFile() throws IOException {

        File original = new File("src\\files\\test01");
        File copy = new File("src\\files\\test02");
        Files.copy(original, copy);
    }

    /**
     * 文件的移动/重命名
     */
    public static void testMoveFile() throws IOException {
        File original = new File("src\\files\\test03");
        File newFile = new File("src\\files\\test04");

        Files.move(original, newFile);
    }

    /**
     *
     */
    public static void eadFileIntoListOfStringsTest() throws IOException {
        File file = new File("src\\files\\test05");
        List<String> list = Lists.newArrayList("hello world", "this is realfighter", "www.xx566.com");
        List<String> lines = Files.readLines(file, Charsets.UTF_8);
        assertThat(list, is(lines));
    }

    /**
     * 获取所有文件中的书本名
     *
     * @throws Exception
     */
    public static void readLinesWithProcessor() throws Exception {
        File file = new File("src\\files\\test05");
        List<String> expectedLines = Lists.newArrayList("Being A Great Cook", "Art is Fun",
                "Be an Architect", "History of Football", "Gardening My Way");
        List<String> readLines = Files.readLines(file, Charsets.UTF_8, new ToListLineProcessor());
        assertThat(expectedLines, is(readLines));
    }

    /**
     * 文件的hash值
     *
     * @throws Exception
     */
    public static void testFilesHashing() throws Exception {
        File file = new File("src\\files\\test05");
        HashCode hash = Files.hash(file, Hashing.md5());
        System.out.println(hash);
    }

    /**
     * 文件写和追加数据
     *
     * @throws IOException
     */
    public static void appendingWritingToFileTest() throws IOException {
        File file = new File("src\\files\\test03");
        //file.deleteOnExit();
        String hamletQuoteStart = "To be, or not to be";
        Files.write(hamletQuoteStart, file, Charsets.UTF_8);
        assertThat(Files.toString(file, Charsets.UTF_8), is(hamletQuoteStart));
        String hamletQuoteEnd = ",that is the question";
        Files.append(hamletQuoteEnd, file, Charsets.UTF_8);
        assertThat(Files.toString(file, Charsets.UTF_8), is(hamletQuoteStart + hamletQuoteEnd));
        String overwrite = "Overwriting the file";
        Files.write(overwrite, file, Charsets.UTF_8);
        assertThat(Files.toString(file, Charsets.UTF_8), is(overwrite));

    }

    /**
     * Files提供的静态方法为一个File对象创建ByteSource：
     */
    public static void createByteSourceFromFileTest() throws Exception {
        File file = new File("src\\files\\test05");
        ByteSource byteSource = Files.asByteSource(file);
        byte[] bytes = byteSource.read();
        assertThat(bytes, is(Files.toByteArray(file)));

    }

    /**
     * ByteSink类表示一个可写的字节。我们可以将字节写入一个文件或另一个字节数组
     */
    public static void testCreateFileByteSink() throws Exception {
        File dest = new File("src\\files\\test04");
        ByteSink byteSink = Files.asByteSink(dest);
        File file = new File("src\\files\\test05");
        byteSink.write(Files.toByteArray(file));
        assertThat(Files.toByteArray(dest), is(Files.toByteArray(file)));
    }

    /**
     * 从ByteSource向ByteSink 复制
     */
    public static void copyToByteSinkTest() throws Exception {
        File dest = new File("src\\files\\test06");
        File source = new File("src\\files\\test05");
        ByteSource byteSource = Files.asByteSource(source);
        ByteSink byteSink = Files.asByteSink(dest);
        byteSource.copyTo(byteSink);
        assertThat(Files.toByteArray(dest), is(Files.toByteArray(source)));
    }

    /**
     * 限制inputstream的大小
     */
    public static void limitByteStreamTest() throws Exception {
        File binaryFile = new File("src\\files\\test06");
        BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(binaryFile));
        InputStream limitedInputStream = ByteStreams.limit(inputStream, 10);
        assertThat(limitedInputStream.available(), is(10));
        assertThat(inputStream.available(), is(218882));
    }

    /**
     * 连接CharStreams
     * CharStreams.join方法接多个InputSupplier实例并连接它们，
     * 这样在逻辑上它们表现为一个InputSupplier实例，并写出它们的内容到一个OutputSupplier实例：
     * 1:我们创建了四个File对象，包括三个需要连接的源文件和一个输出的文件
     * 2:在我们的测试中提供了一个所有的方法getInputSuppliers()，使用了Files.newReaderSupplier静态工厂方法
     * 为每个源文件创建InputSupplier对象
     * 3:之后我们创建InputSupplier来连接InputSupplier集合到一个逻辑InputSupplier
     * 4:使用我们第一步中创建的4个File对象，调用Files.newWriterSupplier工厂方法，创建OutputSupplier
     * 5:使用了另一个private方法joinFiles，每个文件都调用了Files.toString方法来构造我们测试期望的值
     * 6:调用CharStreams.copy方法将提供的InputSuppliers()中的内容写入到OutputSupplier
     * 7:我们验证目标文件是否与三个原始文件包含相同的内容
     */
    public static void joinTest() throws Exception {

        File f1 = new File("src\\files\\test01");
        File f2 = new File("src\\files\\test02");
        File f3 = new File("src\\files\\test03");

        File joinedOutput = new File("src\\files\\test04");
        List<InputSupplier<InputStreamReader>> inputSuppliers = getInputSuppliers(f1, f2, f3);
        InputSupplier<Reader> joinedSupplier = CharStreams.join(inputSuppliers);

        OutputSupplier<OutputStreamWriter> outputSupplier = Files.newWriterSupplier(joinedOutput, Charsets.UTF_8);
        String expectedOutputString = joinFiles(f1, f2, f3);
        CharStreams.copy(joinedSupplier, outputSupplier);
        String joinedOutputString = joinFiles(joinedOutput);
        assertThat(joinedOutputString, is(expectedOutputString));

    }

    /**
     * Files.newInputStreamSupplier
     * @param files
     * @return
     */

    public static void inputStreamSupplierTest() throws IOException {

        String resourceName = "src\\files\\test01";
        InputStream importFileStream = getImportFileStream(resourceName);
        //将字节流向字符流的转换。
        InputStreamReader isr = new InputStreamReader(importFileStream);//读取
        //创建字符流缓冲区
        BufferedReader bufr = new BufferedReader(isr);
        String line;
        while((line = bufr.readLine())!=null){
            System.out.println(line);
        }
        isr.close();

    }

    /**
     * JDK 自带IO流操作
     * @param files
     * @return
     */

    public static void jdkInputStreamTest(String resource) throws IOException {
        InputStream in = new FileInputStream(resource);
        //将字节流向字符流的转换。
        InputStreamReader isr = new InputStreamReader(in);//读取
        //创建字符流缓冲区
        BufferedReader bufr = new BufferedReader(isr);
        String line;
        while((line = bufr.readLine())!=null){
            System.out.println(line);
        }
        isr.close();

    }

    public static void readerAndWriterTest(String resourceName,String writeName) throws IOException {
        Closer closer = Closer.create();
        try {
            File resourceFile = new File(resourceName);
            File destFile = new File(writeName);
            if (resourceFile.exists() && destFile.exists()) {
                BufferedReader reader = Files.newReader(resourceFile, Charsets.UTF_8);
                BufferedWriter writer = Files.newWriter(destFile, Charsets.UTF_8);
                closer.register(reader);
                closer.register(writer);
                String line;
                while((line = reader.readLine())!=null){
                    writer.write(line);
                    System.out.println(line);
                }
            }
        }catch (IOException e){
            throw closer.rethrow(e);
        }finally {
            closer.close();
        }

    }

    private static List<InputSupplier<InputStreamReader>> getInputSuppliers(File... files) {


        List<InputSupplier<InputStreamReader>> list = Lists.newArrayList();
        for (File file : files) {
            list.add(Files.newReaderSupplier(file, Charsets.UTF_8));
        }
        return list;
    }

    private static String joinFiles(File... files) throws IOException {
        StringBuilder builder = new StringBuilder();
        for (File file : files) {
            builder.append(Files.toString(file, Charsets.UTF_8));
        }
        return builder.toString();
    }

    private static InputStream getImportFileStream(final String resourceName) {
        InputStream stream = null;
        File resourceFile = new File(resourceName);
        if (resourceFile.exists()) {
            InputSupplier<FileInputStream> inputStreamSupplier = Files.newInputStreamSupplier(resourceFile);
            try {
                stream = inputStreamSupplier.getInput();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        return stream;
    }


    public static BufferedWriter writeFileStream(String path) {

        OutputStreamWriter outputStreamReader;
        BufferedWriter bufferedWriter = null;
        try {
            outputStreamReader = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
            bufferedWriter = new BufferedWriter(outputStreamReader);
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            e.printStackTrace();
        }

        return bufferedWriter;
    }

    /**
     *  Guava中的Closer类被用来确保所有注册Closeable对象在Closer.close方法被调用时正确的关闭。
     */

    public static void testCloser() throws IOException {
        Closer closer = Closer.create();
        try {
            File destination = new File("src\\files\\test07");
            BufferedReader reader = new BufferedReader(new FileReader("src\\files\\test01"));
            BufferedWriter writer = new BufferedWriter(new FileWriter(destination));
            closer.register(reader);
            closer.register(writer);
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line+ "\n");
            }
        } catch (Throwable t) {
            throw closer.rethrow(t);
        } finally {
            closer.close();
        }
    }

    /**
     * BaseEncoding
     * 在处理二进制数据时，我们有时需要将表示数据的字节转换成可打印的ASCII字符。当然，我们也需要能够将转成原始解码编码字节形式。
     * BaseEncoding是一个抽象类，包含许多静态工厂方法，能够为不同编码方法创建实例。
     */

    public static void encodeDecodeTest() throws Exception {
        File file = new File("src\\files\\test01");
        byte[] bytes = Files.toByteArray(file);
        BaseEncoding baseEncoding = BaseEncoding.base64();
        //将byte数组转为ASCII字符
        String encoded = baseEncoding.encode(bytes);
        assertThat(Pattern.matches("[A-Za-z0-9+/=]+", encoded),is(true));
        assertThat(baseEncoding.decode(encoded),is(bytes));
    }


}
